﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Zatify.WebUI.Infrastructure;
using Zatify.WebUI.Models;
using Zatify.Domain.Abstract;
using Zatify.WebUI.Admin.Helpers;
using Zatify.Domain.Data;

namespace Zatify.WebUI.Controllers
{
    using Zatify.Domain.Entities.Extensions;

    [Authorize]
    public class BusinessProfileController : BaseController
    {
        private IZatifyRepository repository;
        public BusinessProfileController(IZatifyRepository repository)
        {
            this.repository = repository;
        }

        [HttpGet]
        public ActionResult Address()
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            PopulateUSStatesViewData(business.StateCode);

            return View(new BusinessProfileAddressViewModel()
            {
                UserID = business.Login,
                Password = business.Password,
                ConfirmPassword = business.Password,
                Email = business.Email,
                BusinessName = business.BusinessName,
                Web = business.Web,
                BusinessPhone = business.BusinessPhone,
                CellPhone = business.CellPhone,
                TollFreePhone = business.TollFreePhone,
                Fax = business.Fax,
                StreetAddress1 = business.StreetAddress1,
                StreetAddress2 = business.StreetAddress2,
                City = business.City,
                StateCode = business.StateCode,
                ZipCode = business.ZipCode
            });
        }
        [HttpPost]
        public ActionResult Address(BusinessProfileAddressViewModel model)
        {
            if (ModelState.IsValid)
            {
                var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

                business.Password = model.Password;
                business.Email = model.Email;
                business.BusinessName = model.BusinessName;
                business.Web = model.Web ?? String.Empty;
                business.BusinessPhone = model.BusinessPhone;
                business.CellPhone = model.CellPhone ?? String.Empty;
                business.TollFreePhone = model.TollFreePhone ?? String.Empty;
                business.Fax = model.Fax ?? String.Empty;
                business.StreetAddress1 = model.StreetAddress1;
                business.StreetAddress2 = model.StreetAddress2 ?? String.Empty;
                business.City = model.City;
                business.StateCode = model.StateCode;
                business.ZipCode = model.ZipCode;

                var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                    this.repository.BusinessGetBusinessHours(business.BusinessId),
                                    String.Join(",", business.Categories.Select(c => c.CategoryId).ToArray()),
                                    String.Empty, String.Empty, String.Empty, business.Latitude, business.Longitude, 0);
                if (result == 1)
                {
                    return RedirectToAction("Address");
                }
                else
                {
                    switch (result)
                    {
                        case -2:
                            this.ModelState.AddModelError("Email", "Entered Email already exist");
                            break;
                        case -3:
                            this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exist");
                            break;
                        case -4:
                            this.ModelState.AddModelError("BillingZipCode", "Entered Billing Zip Code does not exist");
                            break;
                    }
                }
            }

            PopulateUSStatesViewData(model.StateCode);

            return View(model);
        }

        [HttpGet]
        public ActionResult Description()
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            return View(new BusinessProfileDescriptionViewModel()
            {
                Description = business.Description,
                HasImage = (business.Picture != null && business.Picture.Length > 0)
            });
        }
        [HttpPost]
        public ActionResult Description(BusinessProfileDescriptionViewModel model, HttpPostedFileBase imageUpload)
        {
            if (ModelState.IsValid)
            {
                var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

                business.Description = model.Description;

                if (imageUpload != null && imageUpload.ContentLength > 0)
                {
                    var bytes = new byte[imageUpload.ContentLength];
                    imageUpload.InputStream.Read(bytes, 0, imageUpload.ContentLength);

                    business.Picture = bytes;
                    business.PictureContentType = imageUpload.ContentType;
                }

                var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                    this.repository.BusinessGetBusinessHours(business.BusinessId),
                                    String.Join(",", business.Categories.Select(c => c.CategoryId).ToArray()),
                                    String.Empty, String.Empty, String.Empty, business.Latitude, business.Longitude, 0);
                if (result == 1)
                {
                    return RedirectToAction("Description");
                }
                else
                {
                    switch (result)
                    {
                        case -2:
                            this.ModelState.AddModelError("Email", "Entered Email already exist");
                            break;
                        case -3:
                            this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exist");
                            break;
                        case -4:
                            this.ModelState.AddModelError("BillingZipCode", "Entered Billing Zip Code does not exist");
                            break;
                    }
                }
            }

            return View(model);
        }

        [HttpGet]
        public ActionResult BusinessHours()
        {
            PopulateBusinessHoursViewData();

            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);
            business.BusinessHours = this.repository.BusinessGetBusinessHours(business.BusinessId);

            return View(new BusinessProfileBusinessHoursViewModel()
            {
                SunFrom = business.BusinessHours.SunFrom,
                SunTo = business.BusinessHours.SunTo,
                SunClosed = business.BusinessHours.SunClosed,
                Sun24HoursOpen = business.BusinessHours.SunIs24Open,

                MonFrom = business.BusinessHours.MonFrom,
                MonTo = business.BusinessHours.MonTo,
                MonClosed = business.BusinessHours.MonClosed,
                Mon24HoursOpen = business.BusinessHours.MonIs24Open,

                TueFrom = business.BusinessHours.TueFrom,
                TueTo = business.BusinessHours.TueTo,
                TueClosed = business.BusinessHours.TueClosed,
                Tue24HoursOpen = business.BusinessHours.TueIs24Open,

                WedFrom = business.BusinessHours.WedFrom,
                WedTo = business.BusinessHours.WedTo,
                WedClosed = business.BusinessHours.WedClosed,
                Wed24HoursOpen = business.BusinessHours.WedIs24Open,

                ThuFrom = business.BusinessHours.ThuFrom,
                ThuTo = business.BusinessHours.ThuTo,
                ThuClosed = business.BusinessHours.ThuClosed,
                Thu24HoursOpen = business.BusinessHours.ThuIs24Open,

                FriFrom = business.BusinessHours.FriFrom,
                FriTo = business.BusinessHours.FriTo,
                FriClosed = business.BusinessHours.FriClosed,
                Fri24HoursOpen = business.BusinessHours.FriIs24Open,

                SatFrom = business.BusinessHours.SatFrom,
                SatTo = business.BusinessHours.SatTo,
                SatClosed = business.BusinessHours.SatClosed,
                Sat24HoursOpen = business.BusinessHours.SatIs24Open,
            });
        }
        [HttpPost]
        public ActionResult BusinessHours(BusinessProfileBusinessHoursViewModel model)
        {
            if (!model.MonClosed && !model.Mon24HoursOpen && (model.MonTo == model.MonFrom /*|| model.MonTo < model.MonFrom*/))
            {
                this.ModelState.AddModelError("MonTimeError", "Monday working time incorrect");
            }
            if (!model.TueClosed && !model.Tue24HoursOpen && (model.TueTo == model.TueFrom /*|| model.TueTo < model.TueFrom*/))
            {
                this.ModelState.AddModelError("TueTimeError", "Tuesday working time incorrect");
            }
            if (!model.WedClosed && !model.Wed24HoursOpen && (model.WedTo == model.WedFrom /*|| model.WedTo < model.WedFrom*/))
            {
                this.ModelState.AddModelError("WedTimeError", "Wednesday working time incorrect");
            }
            if (!model.ThuClosed && !model.Thu24HoursOpen && (model.ThuTo == model.ThuFrom /*|| model.ThuTo < model.ThuFrom*/))
            {
                this.ModelState.AddModelError("ThuTimeError", "Thursday working time incorrect");
            }
            if (!model.FriClosed && !model.Fri24HoursOpen && (model.FriTo == model.FriFrom /*|| model.FriTo < model.FriFrom*/))
            {
                this.ModelState.AddModelError("FriTimeError", "Friday working time incorrect");
            }
            if (!model.SatClosed && !model.Sat24HoursOpen && (model.SatTo == model.SatFrom /*|| model.SatTo < model.SatFrom*/))
            {
                this.ModelState.AddModelError("SatTimeError", "Saturday working time incorrect");
            }
            if (!model.SunClosed && !model.Sun24HoursOpen && (model.SunTo == model.SunFrom /*|| model.SunTo < model.SunFrom*/))
            {
                this.ModelState.AddModelError("SunTimeError", "Sunday working time incorrect");
            }

            if (ModelState.IsValid)
            {
                var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

                var businessHours = new BusinessHours()
                {
                    SunFrom = model.SunFrom,
                    SunTo = model.SunTo,
                    SunClosed = model.SunClosed,
                    MonFrom = model.MonFrom,
                    MonTo = model.MonTo,
                    MonClosed = model.MonClosed,
                    TueFrom = model.TueFrom,
                    TueTo = model.TueTo,
                    TueClosed = model.TueClosed,
                    WedFrom = model.WedFrom,
                    WedTo = model.WedTo,
                    WedClosed = model.WedClosed,
                    ThuFrom = model.ThuFrom,
                    ThuTo = model.ThuTo,
                    ThuClosed = model.ThuClosed,
                    FriFrom = model.FriFrom,
                    FriTo = model.FriTo,
                    FriClosed = model.FriClosed,
                    SatFrom = model.SatFrom,
                    SatTo = model.SatTo,
                    SatClosed = model.SatClosed
                };

                var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                   businessHours,
                                   String.Join(",", business.Categories.Select(c => c.CategoryId).ToArray()),
                                   String.Empty, String.Empty, String.Empty, business.Latitude, business.Longitude, 0);

                if (result == 1)
                {
                    return RedirectToAction("BusinessHours");
                }
                else
                {
                    switch (result)
                    {
                        case -2:
                            this.ModelState.AddModelError("Email", "Entered Email already exist");
                            break;
                        case -3:
                            this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exist");
                            break;
                        case -4:
                            this.ModelState.AddModelError("BillingZipCode", "Entered Billing Zip Code does not exist");
                            break;
                    }
                }
            }

            PopulateBusinessHoursViewData();
            return View();
        }

        [HttpGet]
        public ActionResult Payment()
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            PopulateDatePicker(business.CreditCardExpDate.Month, business.CreditCardExpDate.Year);
            PopulateUSStatesViewData(business.BillingStateCode);

            return View(new BusinessProfilePaymentViewModel()
            {
                CreditCardNo = business.CreditCardNo,
                CreditCardName = business.CreditCardName,
                CreditCardExpDate = business.CreditCardExpDate,
                CreditCardExpirationMonth = business.CreditCardExpDate.Month,
                CreditCardExpirationYear = business.CreditCardExpDate.Year,
                CreditCardPin = business.CreditCardPin,

                BillingUse = business.BillingUse,
                BillingAddress1 = (business.BillingUse ? business.StreetAddress1 : business.BillingAddress1),
                BillingAddress2 = (business.BillingUse ? business.StreetAddress2 : business.BillingAddress2),
                BillingCity = (business.BillingUse ? business.City : business.BillingCity),
                BillingStateCode = (business.BillingUse ? business.StateCode : business.BillingStateCode),
                BillingZipCode = (business.BillingUse ? business.ZipCode : business.BillingZipCode),

                BusinessAddress1 = business.StreetAddress1,
                BusinessAddress2 = business.StreetAddress2,
                BusinessCity = business.City,
                BusinessStateCode = business.StateCode,
                BusinessZipCode = business.ZipCode
            });
        }
        [HttpPost]
        public ActionResult Payment(BusinessProfilePaymentViewModel model)
        {
            if ((model.CreditCardExpirationYear < DateTime.Now.Year) || (model.CreditCardExpirationYear == DateTime.Now.Year && model.CreditCardExpirationMonth <= DateTime.Now.Month))
            {
                ModelState.AddModelError("CreditCardExpirationDate", "Credit card expired");
            }

            if (ModelState.IsValid)
            {
                var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

                business.CreditCardNo = model.CreditCardNo;
                business.CreditCardName = model.CreditCardName;
                business.CreditCardExpDate = new DateTime(model.CreditCardExpirationYear, model.CreditCardExpirationMonth, 1);

                business.CreditCardPin = model.CreditCardPin;
                business.BillingAddress1 = model.BillingAddress1;
                business.BillingAddress2 = model.BillingAddress2 ?? String.Empty;
                business.BillingCity = model.BillingCity;
                business.BillingStateCode = (model.BillingUse ? model.BusinessStateCode : model.BillingStateCode);
                business.BillingZipCode = (model.BillingUse ? model.BusinessZipCode : model.BillingZipCode);
                business.BillingUse = model.BillingUse;

                var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                   this.repository.BusinessGetBusinessHours(business.BusinessId),
                                   String.Join(",", business.Categories.Select(c => c.CategoryId).ToArray()),
                                   String.Empty, String.Empty, String.Empty, business.Latitude, business.Longitude, 0);

                if (result == 1)
                {
                    return RedirectToAction("Payment");
                }
                else
                {
                    switch (result)
                    {
                        case -2:
                            this.ModelState.AddModelError("Email", "Entered Email already exist");
                            break;
                        case -3:
                            this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exist");
                            break;
                        case -4:
                            this.ModelState.AddModelError("BillingZipCode", "Entered Billing Zip Code does not exist");
                            break;
                    }
                }
            }

            PopulateDatePicker(model.CreditCardExpDate.Month, model.CreditCardExpDate.Year);
            PopulateUSStatesViewData(model.BillingStateCode);

            return View(model);
        }

        #region Categories

        [HttpGet]
        public ActionResult CategoriesEdit()
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            var selectedCategories = business.Categories.ToList();

            return View(new BusinessProfileCategoriesViewModel()
            {
                SelectegCategoriesIds = String.Join(",", (from cat in selectedCategories select cat.CategoryId)),
                SelectedCategories = selectedCategories,
                Categories = repository.CategoriesGetAll().ToList()
            });
        }

        [HttpGet]
        public ActionResult Categories(int? categoryId)
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            var selectedCategories = business.Categories.ToList();

            return View(new BusinessProfileCategoriesViewModel()
            {
                SelectegCategoriesIds = String.Join(",", (from cat in selectedCategories select cat.CategoryId)),
                SelectedCategories = selectedCategories,
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == categoryId),
                Categories = repository.CategoriesGetAll().Where(c => c.ParentId == categoryId).ToList()
            });
        }

        [HttpPost]
        public ActionResult Categories(BusinessProfileCategoriesViewModel model)
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                    this.repository.BusinessGetBusinessHours(business.BusinessId),
                                    model.SelectegCategoriesIds,
                                    (model.NewCategoryName1IsChecked ? model.NewCategoryName1 : String.Empty),
                                    (model.NewCategoryName2IsChecked ? model.NewCategoryName2 : String.Empty),
                                    (model.NewCategoryName3IsChecked ? model.NewCategoryName3 : String.Empty),
                                     business.Latitude, business.Longitude, 0);

            return RedirectToAction("CategoriesEdit");
        }

        [HttpPost]
        public ActionResult CategoriesRemove(string categoriesIds)
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            var result = this.repository.BusinessUpdate(User.SecurityToken.Value, business,
                                    this.repository.BusinessGetBusinessHours(business.BusinessId),
                                    categoriesIds,
                                    String.Empty, String.Empty, String.Empty, business.Latitude, business.Longitude, 0);

            return RedirectToAction("CategoriesEdit");
        }

        #endregion

        #region Promotions

        private NewPromotionViewModel NewPromotion
        {
            get
            {
                return (NewPromotionViewModel)Session["NewPromotion"];
            }
            set
            {
                Session["NewPromotion"] = value;
            }
        }

        [HttpGet]
        public ActionResult Promotions()
        {
            return View(new BusinessProfilePromotionsViewModel()
            {
                UserTimeZoneOffset = (this.User.TimeZoneOffset * -1),
                Promotions = this.repository.PromotionsGetByBusinessToken(User.SecurityToken.Value).ToList()
            });
        }

        public ActionResult Add()
        {
            var businessCategories = this.repository.BusinessGetByToken(User.SecurityToken.Value).Categories.ToList();
            var perPush = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush;
            var flatFee = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().FixedCost;

            NewPromotion = new NewPromotionViewModel()
            {
                PromotionCompaignCost = perPush,
                PromotionCompaignFlatFees = flatFee,
                CategoriesCostFlatFee = flatFee,
                CategoriesCostPerPush = perPush,
                PromotionCategories = new List<Category>()
            };

            return RedirectToAction("NewPromotionStep1");
        }

        public ActionResult DeletePromotion(int id)
        {
            this.repository.PromotionDeleteByBusinessTokenAndId(User.SecurityToken.Value, id);

            return RedirectToAction("Promotions");
        }

        #region 1st Step - Selecting Promo's Categories

        [HttpGet]
        public ActionResult NewPromotionStep1(int? id)
        {
            if (NewPromotion == null)
                return RedirectToAction("Add");

            var model = new NewPromotionStep1ViewModel()
            {
                BaseCost = NewPromotion.PromotionCompaignCost,
                FlatFee = NewPromotion.PromotionCompaignFlatFees,
                SelectedCategories = NewPromotion.PromotionCategories,
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == id),
                Categories = (id.HasValue ? this.repository.CategoriesGetAll().Where(c => c.ParentId == id).ToList()
                            : this.repository.CategoriesGetAll().Where(c => !c.ParentId.HasValue).ToList()),

                SelectedCategoriesIds = NewPromotion.PromotionCategories.Count > 0 ?
                                        NewPromotion.PromotionCategories.Select(c => c.CategoryId.ToString()).Aggregate((cur, nxt) => cur + "," + nxt) : String.Empty
            };

            return View(model);
        }

        [HttpPost]
        public ActionResult NewPromotionStep1(string selectedCategoriesIds)
        {
            if (String.IsNullOrWhiteSpace(selectedCategoriesIds))
                ModelState.AddModelError("Promotion_SelectedCategoriesIds", "Promotion's categories were not selected");

            if (ModelState.IsValid)
            {
                var result = this.repository.Business_AddPromotion(User.SecurityToken.Value);

                if (result.IdResult == 1)
                {
                    var resultArray = result.Result.Split(';');
                    var promotionId = Int32.Parse(resultArray[0]);
                    var ratePerPush = Double.Parse(resultArray[1]);
                    var fixedCost = Double.Parse(resultArray[2]);

                    var categoryAddResult = this.repository.Business_AddPromotionCategories(User.SecurityToken.Value, promotionId, selectedCategoriesIds);

                    if (categoryAddResult.IdResult == 1)
                    {
                        NewPromotion.PromotionId = promotionId;

                        return RedirectToAction("NewPromotionStep2");
                    }
                    else
                    {
                        TempData["Error"] = "Error during adding promotion's categories.";
                    }
                }
                else if (result.IdResult == -2)
                {
                    TempData["Error"] = "Credit card expired!";
                }
            }

            return View("NewPromotionStep1", new NewPromotionStep1ViewModel()
            {
                BaseCost = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                FlatFee = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().FixedCost,
                SelectedCategories = NewPromotion.PromotionCategories,
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == null),
                Categories = (NewPromotion.PromotionId > 0 ? this.repository.CategoriesGetAll().Where(c => c.ParentId == NewPromotion.PromotionId).ToList()
                                : this.repository.CategoriesGetAll().Where(c => !c.ParentId.HasValue).ToList())
                //this.repository.BusinessGetByToken(User.SecurityToken.Value).Categories.ToList()
            });
        }

        [HttpPost]
        public ActionResult PromotionCategoriesAdd(string selectedCategoriesIds)
        {
            if (!String.IsNullOrWhiteSpace(selectedCategoriesIds))
            {
                var ids = selectedCategoriesIds.Split(',').Select(id => Int32.Parse(id)).ToList();

                ids.ForEach(id =>
                {
                    var category = this.repository.Categories.FirstOrDefault(c => c.CategoryId == id);

                    if (category != null && !NewPromotion.PromotionCategories.Select(c => c.CategoryId).Contains(category.CategoryId))
                    {
                        if (category.IsSingleSelection)
                            NewPromotion.PromotionCategories.RemoveAll(x => x.ParentId == category.ParentId);

                        NewPromotion.PromotionCategories.Add(category);
                    }
                });
            }

            return RedirectToAction("NewPromotionStep1");
        }

        [HttpGet]
        public ActionResult PromotionCategoriesRemove(int id)
        {
            NewPromotion.PromotionCategories.Remove(NewPromotion.PromotionCategories.FirstOrDefault(c => c.CategoryId == id));

            return RedirectToAction("NewPromotionStep1");
        }

        #endregion

        #region 2nd Step - Selecting Promo's Distance

        [HttpGet]
        public ActionResult NewPromotionStep2()
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep1");

            var feets = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "feet").OrderBy(p => p.ProximityRadiusId).ToList();
            var miles = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "miles").OrderBy(p => p.ProximityRadiusId).ToList();

            PopulateFeetsSelect(feets);
            PopulateOtsideRadiuses();

            return View(new NewPromotionStep2ViewModel()
            {
                PromotionCompaignCost = NewPromotion.PromotionCompaignCost,
                PromotionCompaignFlatFee = NewPromotion.PromotionCompaignFlatFees,
                PromotionId = NewPromotion.PromotionId,
                ProximityRadiusesFeets = feets,
                ProximityRadiusesMiles = miles
            });
        }

        [HttpPost]
        public ActionResult NewPromotionStep2(NewPromotionStep2ViewModel model)
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep2");

            if (model.SelectedProximityRadiusId <= 0)
                ModelState.AddModelError("SelectedProximityRadiusId", "Proximity Radius was not selected");

            if (model.IsCustomRangeSelected && String.IsNullOrWhiteSpace(model.CustomRangeValue))
                ModelState.AddModelError("CutomRange", "Custom Range was not entered");

            var feets = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "feet").OrderBy(p => p.ProximityRadiusId).ToList();
            var miles = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "miles").OrderBy(p => p.ProximityRadiusId).ToList();

            if (ModelState.IsValid)
            {
                var isRegisteredOutSideOfZIP = model.RadiusCode == "ZIP";
                var isRegisteredOutSideOfState = model.RadiusCode == "STATE";
                var isRegisteredOutSideOfCity = model.RadiusCode == "CITY";

                var result = this.repository.Promotion_ProximityRadius_Update(User.SecurityToken.Value, model.PromotionId, model.SelectedProximityRadiusId,
                      (!String.IsNullOrWhiteSpace(model.CustomRangeValue)) ? (Nullable<Int32>)Int32.Parse(model.CustomRangeValue) : null,
                      model.IsOver200MilesSelected,
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfZIP) : false),
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfState) : false),
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfCity) : false));


                NewPromotion.ProximityCostPerPush = 0;
                NewPromotion.ProximityCostFlatFee = 0;
                NewPromotion.PromotionCompaignFlatFees = model.PromotionCompaignFlatFee;
                NewPromotion.PromotionCompaignCost = model.PromotionCompaignCost;

                NewPromotion.SelectedRadiusText = String.Format("{1} {0}", (model.IsFeetsSelected ? "feets" : "miles"),
                    (model.IsFeetsSelected ? feets.FirstOrDefault(x => x.ProximityRadiusId == model.SelectedProximityRadiusId).ToRadius.ToString() :
                    (model.IsCustomRangeSelected ? model.CustomRangeValue :
                    (model.IsOver200MilesSelected ? "Over 200" : miles.FirstOrDefault(x => x.ProximityRadiusId == model.SelectedProximityRadiusId).ToRadius.ToString()))));

                return RedirectToAction("NewPromotionStep3");
            }

            PopulateFeetsSelect(feets);
            PopulateOtsideRadiuses();

            return View(new NewPromotionStep2ViewModel()
            {
                PromotionCompaignCost = NewPromotion.PromotionCompaignCost,
                PromotionCompaignFlatFee = NewPromotion.PromotionCompaignFlatFees,
                PromotionId = model.PromotionId,
                IsRegisteredOutside = false,
                ProximityRadiusesFeets = feets,
                ProximityRadiusesMiles = miles
            });
        }

        private void PopulateFeetsSelect(List<ProximityRadius> feets)
        {
            var feetsSelectList = new List<SelectListItem>();

            feets.ForEach(f =>
            {
                feetsSelectList.Add(new SelectListItem()
                {
                    Text = f.ToRadius.ToString(),
                    Value = f.ProximityRadiusId.ToString() + ";" + f.FixedCost.ToString("0.00") + ";" + f.RatePerPush.ToString("0.00"),
                });
            });

            ViewData["ProximityFeets"] = feetsSelectList;
        }

        private void PopulateOtsideRadiuses()
        {
            var outsideRadiusesSelectList = new List<SelectListItem>();

            this.repository.ProximityRadiusesOutside.ToList().ForEach(r =>
            {
                outsideRadiusesSelectList.Add(new SelectListItem()
                {
                    Text = r.Description,
                    Value = r.ProximityRadiusOutsideCode + ";" + r.FixedCost.ToString("0.00") + ";" + r.RatePerPush.ToString("0.00"),
                });
            });

            ViewData["OutsideRadiuses"] = outsideRadiusesSelectList;
        }

        #endregion

        #region 3rd Step - Selecting Promo's Scheduling

        [HttpGet]
        public ActionResult NewPromotionStep3()
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep1");

            var baseCostsTiming = this.repository.BaseCostTimings.ToList();

            return View(new NewPromotionStep3ViewModel()
            {
                PromotionId = NewPromotion.PromotionId,
                BaseCostTimingId = 0,//PromotionConstants.TIMING_INSTANT_NOW,
                PromotionCompaignCost = NewPromotion.PromotionCompaignCost,
                PromotionCompaignFlatFee = NewPromotion.PromotionCompaignFlatFees,

                BaseCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                InstantNowFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().FixedCost,
                InstantNowCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().RatePerPush,

                ScheduledAtFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().FixedCost,
                ScheduledAtCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().RatePerPush,

                DateRangeWithTimeIntervalFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().FixedCost,
                DateRangeWithTimeIntervalCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().RatePerPush
            });
        }

        [HttpPost]
        public ActionResult NewPromotionStep3(NewPromotionStep3ViewModel model)
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep3");

            if (model.BaseCostTimingId <= 0)
                ModelState.AddModelError("SelectedBaseCostTimingId", "Campaign Timing was not selected");

            var business = repository.BusinessGetByToken(User.SecurityToken.Value);

            if (model.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT)
            {
                if (!model.BaseCostTimingScheduledAtDate.HasValue)
                {
                    ModelState.AddModelError("BaseCostTimingScheduledAt_EmptyDate", "Select 'Scheduled at' date");
                }
                else
                {
                    model.BaseCostTimingScheduledAtDate = new DateTime(
                            model.BaseCostTimingScheduledAtDate.Value.Year, model.BaseCostTimingScheduledAtDate.Value.Month, model.BaseCostTimingScheduledAtDate.Value.Day,
                            model.BaseCostTimingScheduledAtTime.Value.Hours, model.BaseCostTimingScheduledAtTime.Value.Minutes, model.BaseCostTimingScheduledAtTime.Value.Seconds);
                }
            }
            else if (model.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE)
            {
                if (!model.BaseCostTimingStartsDate.HasValue || !model.BaseCostTimingEndsDate.HasValue)
                {
                    ModelState.AddModelError("BaseCostTimingStartsEndsDates_Empty", "Select 'Start Date' and 'End Date' intervals");
                }
                else if (model.BaseCostTimingStartsDate.Value > model.BaseCostTimingEndsDate.Value)
                {
                    ModelState.AddModelError("BaseCostTimingStartsEndsDates_EndsDateGreater", "'End Date' must be greater than 'Start Date'");
                }
                else if (!model.BaseCostTimingStartsTime.HasValue || !model.BaseCostTimingEndsTime.HasValue)
                {
                    ModelState.AddModelError("BaseCostTimingStartsEndsHours_Empty", "Select 'Starts' and 'Ends' hours intervals");
                }
                else if (model.BaseCostTimingStartsDate.Value.Equals(model.BaseCostTimingEndsDate.Value) && (model.BaseCostTimingEndsTime.Value < model.BaseCostTimingStartsTime.Value))
                {
                    ModelState.AddModelError("BaseCostTimingStartsEndsHours_EndsDateGreater", "'Ends' hours must be greater than 'Starts' hours");
                }
                else
                {
                    model.BaseCostTimingStartsDate = new DateTime(
                            model.BaseCostTimingStartsDate.Value.Year, model.BaseCostTimingStartsDate.Value.Month, model.BaseCostTimingStartsDate.Value.Day,
                            model.BaseCostTimingStartsTime.Value.Hours, model.BaseCostTimingStartsTime.Value.Minutes, model.BaseCostTimingStartsTime.Value.Seconds);

                    model.BaseCostTimingEndsDate = new DateTime(
                        model.BaseCostTimingEndsDate.Value.Year, model.BaseCostTimingEndsDate.Value.Month, model.BaseCostTimingEndsDate.Value.Day,
                        model.BaseCostTimingEndsTime.Value.Hours, model.BaseCostTimingEndsTime.Value.Minutes, model.BaseCostTimingEndsTime.Value.Seconds);

                    model.BaseCostTimingScheduledAtDate = model.BaseCostTimingStartsDate.HasValue ?
                        model.BaseCostTimingStartsDate.Value : model.BaseCostTimingStartsDate;
                }
            }

            if (ModelState.IsValid)
            {
                NewPromotion.PromotionCompaignFlatFees = model.PromotionCompaignFlatFee;
                NewPromotion.PromotionCompaignCost = model.PromotionCompaignCost;
                NewPromotion.TimingCostPerPush = model.TimingCost;

                NewPromotion.SelectedTimingText = String.Format("{0}",
                    (model.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW ? "Instant now" :
                    (model.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT ? "Scheduled at " + model.BaseCostTimingScheduledAtDate.Value.ToString("MM/dd/yy hh:mm tt") :
                    model.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE ?
                    String.Format("Date range with time interval from {0} to {1}; {2} - {3}",
                                    model.BaseCostTimingStartsDate.Value.ToString("MM/dd/yy"),
                                    model.BaseCostTimingEndsDate.Value.ToString("MM/dd/yy"),
                                    DateTime.Parse(model.BaseCostTimingStartsTime.Value.ToString()).ToString("hh:mm tt"),
                                    DateTime.Parse(model.BaseCostTimingEndsTime.Value.ToString()).ToString("hh:mm tt")) : String.Empty)));
                
                model.BaseCostTimingScheduledAtDate = model.BaseCostTimingScheduledAtDate == null ? (DateTime?)null : model.BaseCostTimingScheduledAtDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingStartsDate = model.BaseCostTimingStartsDate == null ? (DateTime?)null : model.BaseCostTimingStartsDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingEndsDate = model.BaseCostTimingEndsDate == null ? (DateTime?)null : model.BaseCostTimingEndsDate.Value.ToUTC(business.Gmt);
                                
                var result = this.repository.Promotion_BaseCostTiming_Update(User.SecurityToken.Value, model.PromotionId, model.BaseCostTimingId,
                                         model.BaseCostTimingScheduledAtDate ?? model.ClientDateTime.ToUTC(business.Gmt),
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null,
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null);

                return RedirectToAction("NewPromotionStep4");
            }

            var baseCostsTiming = this.repository.BaseCostTimings.ToList();

            return View(new NewPromotionStep3ViewModel()
            {
                PromotionId = NewPromotion.PromotionId,
                BaseCostTimingId = model.BaseCostTimingId,
                PromotionCompaignCost = NewPromotion.PromotionCompaignCost,
                PromotionCompaignFlatFee = NewPromotion.PromotionCompaignFlatFees,

                BaseCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                InstantNowFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().FixedCost,
                InstantNowCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().RatePerPush,

                ScheduledAtFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().FixedCost,
                ScheduledAtCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().RatePerPush,

                DateRangeWithTimeIntervalFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().FixedCost,
                DateRangeWithTimeIntervalCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().RatePerPush
            });
        }

        #endregion

        #region 4th Step - Selecting Promo's Information

        [HttpGet]
        public ActionResult NewPromotionStep4()
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep1");

            return View(new NewPromotionStep4ViewModel()
            {
                PromotionId = NewPromotion.PromotionId,
                PromotionCompaignFlatFee = NewPromotion.PromotionCompaignFlatFees,
                PromotionCompaignCost = NewPromotion.PromotionCompaignCost,
                SingleUseOnly = NewPromotion.SingleUseOnly,
                Match = NewPromotion.Match
                //TimingCost = NewPromotion.TimingCost
            });
        }

        [HttpPost]
        public ActionResult NewPromotionStep4(NewPromotionStep4ViewModel model, string imagePath)
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep4");

            if (this.ModelState.IsValid)
            {
                if (String.IsNullOrWhiteSpace(imagePath))
                {
                    this.ModelState.AddModelError("PromotionImage", "Select Promotion Image");
                    return View(model);
                }
            }

            if (this.ModelState.IsValid)
            {
                if ((this.UploadedTempImageBytes != null && this.UploadedTempImageBytes.Length > 0) && !String.IsNullOrEmpty(this.UploadedTempImageMimeType))
                {
                    model.Picture = this.UploadedTempImageBytes;
                    model.PictureContentType = this.UploadedTempImageMimeType;
                }
                //if (!String.IsNullOrWhiteSpace(imagePath))
                //{
                //    var filePath = Server.MapPath(imagePath);
                //    var fileInfo = new System.IO.FileInfo(filePath);

                //    using (var fsStream = System.IO.File.OpenRead(filePath))
                //    {
                //        model.Picture = new byte[fsStream.Length];
                //        model.PictureContentType = "image/" + fileInfo.Extension.Replace(".", String.Empty);
                //        fsStream.Read(model.Picture, 0, (int)fsStream.Length);
                //    }
                //}
                //else
                //{
                //    this.ModelState.AddModelError("PromotionImage", "Select Promotion Image");
                //    return View(model);
                //}

                var result = this.repository.Promotion_UpdateBudget(User.SecurityToken.Value, model.PromotionId, model.BudgetAmount.Value, model.PromotionName, model.PromotionText,
                                    model.Picture, model.PictureContentType, model.SingleUseOnly, model.Match);

                if (result == 1)
                {
                    NewPromotion.Budget = model.BudgetAmount ?? 0;
                    NewPromotion.Name = model.PromotionName;
                    NewPromotion.Text = model.PromotionText;
                    NewPromotion.SingleUseOnly = model.SingleUseOnly;
                    NewPromotion.Match = model.Match;
                    return RedirectToAction("NewPromotionStep5");
                }
            }

            return View(model);
        }

        public ActionResult PromoImageUploadControl()
        {
            return PartialView("_ImageUploadControl");
        }

        #endregion

        #region 5th Step - View Promo's Information and Submiting

        [HttpGet]
        public ActionResult NewPromotionStep5()
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep1");

            NewPromotion.Promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, NewPromotion.PromotionId);
            NewPromotion.MaxPushes = (int)((NewPromotion.Budget - NewPromotion.PromotionCompaignFlatFees) / NewPromotion.PromotionCompaignCost);

            return View(NewPromotion);
        }

        [HttpPost]
        public ActionResult NewPromotionStep5End(NewPromotionViewModel model)
        {
            if (NewPromotion == null)
                return RedirectToAction("NewPromotionStep5");

            var payInfo = this.repository.Promotion_GetPayInfo_Result(User.SecurityToken.Value, model.PromotionId);
            var payResult = String.Empty;
            decimal sumPay = 0;
            decimal sumRest = 0;

            if (payInfo.IdResult != 1)
            {
                //ModelState.AddModelError("GetPaymentInfoError", "Error occured during submiting promotion");
                TempData["PaymentError"] = "Error occured during getting payment info promotion";
                return RedirectToAction("NewPromotionStep5");
            }

            if (payInfo.PromoRest.Value > 0 && payInfo.PromoRest.Value < payInfo.CampaignBudget.Value)
            {
                var charge = (payInfo.CampaignBudget.Value - payInfo.PromoRest.Value);

                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = payInfo.PromoRest.Value;
            }
            else if (payInfo.PromoRest.Value == 0)
            {
                var charge = payInfo.CampaignBudget.Value;

                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = 0;
            }
            else if (payInfo.PromoRest.Value >= payInfo.CampaignBudget.Value)
            {
                // DON'T CHARGE
                sumPay = 0;
                sumRest = payInfo.CampaignBudget.Value;
            }

            if (!String.IsNullOrWhiteSpace(payResult))
            {
                //ModelState.AddModelError("PaymentError", payResult);
                TempData["PaymentError"] = payResult;
                return RedirectToAction("NewPromotionStep5");
            }

            try
            {
                var result = this.repository.Promotion_Submit(User.SecurityToken.Value, model.PromotionId, sumPay, sumRest);

                if (result != 1)
                    throw new Exception(String.Format("Error code: {0}", result));
            }
            catch (Exception exc)
            {
                TempData["PaymentError"] = String.Format("Error occured during submiting promotion. {0}", exc.Message);
                return RedirectToAction("NewPromotionStep5");
            }

            NewPromotion = null;

            return RedirectToAction("Promotions");
        }

        #endregion

        #endregion

        #region Methods

        public FileContentResult GetCurrentBusinessPhoto(int w, int h)
        {
            var business = this.repository.BusinessGetByToken(User.SecurityToken.Value);

            if (business != null && business.Picture != null)
            {
                var newSizedImg = Zatify.Domain.Helpers.Helper.ScaleImage(business.Picture, w, h);
                byte[] newSizedImgBytes = Zatify.Domain.Helpers.Helper.ImageToByteArray(newSizedImg);

                return File(newSizedImgBytes, business.PictureContentType);
            }
            else
            {
                var newSizedImg = Zatify.Domain.Helpers.Helper.ScaleImage(System.IO.File.ReadAllBytes(Server.MapPath("~/Content/zatify/images/no_image.jpg")), w, h);
                byte[] newSizedImgBytes = Zatify.Domain.Helpers.Helper.ImageToByteArray(newSizedImg);
                return File(newSizedImgBytes, "image/jpeg");
            }
        }

        public FileContentResult GetPromotionPicture(int id, int w, int h)
        {
            var promotion = this.repository.PromotionGetById(id);

            if (promotion != null && promotion.Picture != null)
            {
                var newSizedImg = Zatify.Domain.Helpers.Helper.ScaleImage(promotion.Picture, w, h);
                byte[] newSizedImgBytes = Zatify.Domain.Helpers.Helper.ImageToByteArray(newSizedImg);

                return File(newSizedImgBytes, promotion.PictureContentType);
            }
            else
            {
                var newSizedImg = Zatify.Domain.Helpers.Helper.ScaleImage(System.IO.File.ReadAllBytes(Server.MapPath("~/Content/zatify/images/no_image.jpg")), w, h);
                byte[] newSizedImgBytes = Zatify.Domain.Helpers.Helper.ImageToByteArray(newSizedImg);

                return File(newSizedImgBytes, "image/jpeg");
            }
        }

        private void PopulateBusinessHoursViewData()
        {
            ViewData["BusinessHours"] = Helper.GetBusinessHoursSelectList();
        }

        private void PopulateUSStatesViewData(string stateCode)
        {
            ViewData["USStates"] =
                (from state in repository.USStates
                 select new SelectListItem()
                 {
                     Text = state.StateName,
                     Value = state.StateCode,
                     Selected = (!String.IsNullOrEmpty(stateCode) && state.StateCode == stateCode)
                 }).ToList();
        }

        private void PopulateDatePicker(int month, int year)
        {
            var months = new List<SelectListItem>();
            var years = new List<SelectListItem>();

            for (int i = 1; i <= 12; i++)
            {
                months.Add(new SelectListItem()
                {
                    Text = i.ToString(),
                    Value = i.ToString(),
                    Selected = i == month
                });
            }

            ViewData["Months"] = months;

            for (int i = DateTime.Now.Year; i <= (DateTime.Now.Year + 10); i++)
            {
                years.Add(new SelectListItem()
                {
                    Text = i.ToString(),
                    Value = i.ToString(),
                    Selected = i == year
                });
            }

            ViewData["Years"] = years;
        }


        #endregion
    }
}
